<?php
declare (strict_types = 1);

namespace app\admin\controller\erp;

use app\admin\controller\AuthController;
use app\admin\model\erp\ErpVoucher;
use app\admin\model\erp\ErpVoucherPeriod;
use app\admin\model\system\SystemMenus;
use think\facade\Db;
use think\Request;

class FinanceVoucher extends AuthController
{
    /**
     * 显示列表
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function index(Request $req)
    {
        if ($req->isAjax()) {
            $data = [];
            $page = $req->param('page/d', 1);
            $limit = $req->param('limit/d', 15);

            $start_at = $req->param('start_at');
            if ( !is_null($start_at) && strlen($start_at) && preg_match("/^\d{4}-\d{1,2}$/s",$start_at) ) {
                $month = date('Ym',strtotime($start_at.'-01'));
            } else {
                $month = date('Ym');
            }
            $where = "`period` = '".$month."'";
            $status = $req->param('status');
            if ( !is_null($status) && strlen($status)) {
                $where .= " AND `status`='".$status."'";
            }
            $description = $req->param('description');
            if ( !is_null($description) && strlen($description)) {
                $where .= " AND `description` LIKE '%".$description."%'";
            }
            $period_code = $req->param('period_code');
            if ( !is_null($period_code) && strlen($period_code)) {
                $where .= " AND `period_code` LIKE '%".$period_code."%'";
            }
            $pageX = ($page - 1) * $limit;
            $list = Db::query("SELECT `a`.`description`,`a`.`market`,`a`.`check_uid`,`a`.`create_uid`,`a`.`status`,`a`.`luck`,`a`.`order_no`,`t`.`*` FROM ( SELECT * FROM `bb_erp_voucher_period` WHERE ".$where." ORDER BY `period_code` DESC LIMIT ".$pageX.", ".$limit.") as a LEFT JOIN `bb_erp_voucher` `t` ON `a`.`period_code` = `t`.`period_code` ORDER BY t.period_code DESC,t.position ASC");
            //echo Db::getLastSql();
            $count = Db::query("SELECT count(id) as total FROM `bb_erp_voucher_period` WHERE ".$where." LIMIT 1");

            $data['count'] = $count[0]['total'];
            $data['data'] = $list;
            //echo $query->getLastSql();die;
            $data['code'] = 0;
            $data['period'] = $month;
            $data['luck_btn'] = $month < date('Ym') && $data['count'] > 0 ? 1 : 0;
            $data['luck'] = isset($list[0]['luck']) ? $list[0]['luck'] : 0;
            $data['msg'] = '';
            $users = Db::name('system_admin')->column('real_name','id');
            foreach ($data['data'] as &$val) {
                $val['period_at'] = $val['period_at'] ? date('Y-m-d',$val['period_at']) : '--/--';
                $val['debit'] = $val['debit'] ? number_format($val['debit'],2,'.','') : '';
                $val['credit'] = $val['credit'] ? number_format($val['credit'],2,'.','') : '';
                $val['check_user'] = isset($users[$val['check_uid']]) ? $users[$val['check_uid']] : '';
                $val['create_user'] = isset($users[$val['create_uid']]) ? $users[$val['create_uid']] : 'SYSTEM';
            }
            return json($data);
        }

        $sonAuth = SystemMenus::getSonAuth($req->controller(), $req->action(),array_keys($this->auth));

        $this->assign('sonAuth', $sonAuth);
        return $this->fetch();
    }
    /**
     * 审核/反审核
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function check(Request $req)
    {
        if($req->isPost()) {
            $period_code = $req->param('period_code/d', 0);
            if (!$period_code) $this->error('参数错误');
            $period = ErpVoucherPeriod::where('period_code', $period_code)->find();
            if (!$period) $this->error('参数错误');
            if($period['luck']==1)  $this->error('所属会计期间已锁帐、不能执行此操作');
            $status = $period['status'] ? 0 : 1;
            $res = ErpVoucherPeriod::where('id',$period['id'])->update(
                [
                    'status' => $status,
                    'check_uid' => $this->adminId > 0 ? $this->adminId : 0,
                    'update_at' => time(),
                ]
            );
            if($res) {
                $this->success();
            } else {
                $this->error();
            }
        }
    }

    /**
     * 锁帐/反锁帐
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function luck(Request $req)
    {
        if($req->isPost()) {
            $period = $req->param('period/d', 0);
            if (!$period || $period > date('Ym')) $this->error('参数错误');
            $period_data = ErpVoucherPeriod::where('period', $period)->find();
            if (!$period_data) $this->error('参数错误');

            if(ErpVoucherPeriod::where('period', $period)->where('status',0)->find()) $this->error('该期间有未审核凭证、不能执行锁帐操作');
            $luck = $period_data['luck'] ? 0 : 1;
            $res = ErpVoucherPeriod::where('period','=',$period)->update(
                [
                    'luck' => $luck,
                    'update_at' => time(),
                ]
            );
            if($res) {
                $this->success();
            } else {
                $this->error();
            }
        }
    }

    /**
     * 重新排序
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function position(Request $req)
    {
        if($req->isPost()) {
            $period = $req->param('period/d', 0);
            if (!$period || $period > date('Ym')) $this->error('参数错误');
            $period_code = ErpVoucherPeriod::where('period', $period)->max('period_code');
            if (!$period_code) $this->error('该期间无凭证');
            $max_id = intval(substr((string) $period_code,6));
            $count = ErpVoucherPeriod::where('period', $period)->count('id');
            if($max_id == $count) {
                $this->error('该期间凭证无间断、无需执行排序操作');
            }
            if(ErpVoucherPeriod::where('period', $period)->where('luck',1)->find()) $this->error('该期间已锁帐、不能执行排序操作');

            $periods = ErpVoucherPeriod::where('period', $period)->order('period_code ASC')->column('id,period,period_code','id');
            ErpVoucherPeriod::beginTrans();
            try {
                $period_code = $period . '0001';
                $time = time();
                foreach($periods as $val) {
                    $data = [
                        'period_code' => $period_code,
                        'update_at' => $time,
                    ];
                    $res = ErpVoucherPeriod::where('id', $val['id'])->update($data);
                    if (!$res) {
                        throw new \think\Exception('凭证主表排序失败！');
                    }
                    $res = ErpVoucher::where('period_code', $val['period_code'])->update($data);
                    if (!$res) {
                        throw new \think\Exception('凭证副表排序失败！');
                    }
                    $period_code++;
                }
                ErpVoucherPeriod::commitTrans();
            } catch (\Exception $e) {
                ErpVoucherPeriod::rollbackTrans();
                $this->error($e->getMessage());
            }
            $this->success('操作成功!');
        }
    }

    /**
     * 查看
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function show(Request $req)
    {
        $period_code = $req->param('period_code/d',0);
        if(!$period_code) $this->error('参数错误','', -1);
        $period = ErpVoucherPeriod::where('period_code', $period_code)->find();
        if(!$period) $this->error('参数错误','', -1);
        $data = [];
        $debit = 0;
        $credit = 0;
        $num = 0;
        $vouchers = $period->vouchers()->order('position ASC')->select()->toArray();
        foreach($vouchers as $voucher) {
            $num++;
            $debit += round($voucher['debit'],2);
            $credit += round($voucher['credit'],2);
            $data[] = [
                'description' => $period['description'],
                'market' => $period['market'],
                'code_name' => $voucher['code_name'],
                'debit' => $voucher['debit'] ? number_format($voucher['debit'],2,'.','') : '',
                'credit' => $voucher['credit'] ? number_format($voucher['credit'],2,'.','') : '',
            ];
        }
        $data[] = [
            'description' => '',
            'market' => '',
            'code_name' => '合计',
            'debit' => $debit ? number_format($debit,2,'.','') : '',
            'credit' => $credit ? number_format($credit,2,'.','') : '',
        ];
        $users = Db::name('system_admin')->column('real_name','id');
        $period['check_user'] = isset($users[$period['check_uid']]) ? $users[$period['check_uid']] : '';
        $period['create_user'] = isset($users[$period['create_uid']]) ? $users[$period['create_uid']] : 'SYSTEM';
        $sonAuth = SystemMenus::getSonAuth($req->controller(), $req->action(),array_keys($this->auth));
        $this->assign('sonAuth', $sonAuth);
        $this->assign('data', $data);
        $this->assign('period', $period);
        $this->assign('num', $num);
        return $this->fetch();
    }

    /**
     * 创建资源.
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function add(Request $req)
    {
        if($req->isPost()) {
            $period = $req->param('period','');
            $period_at = $req->param('period_at','');
            if(!preg_match("/^\d{4}-\d{2}$/s",$period)) $this->error('会计期间为年份+月份格式');
            if(!preg_match("/^\d{4}-\d{2}-\d{2}$/s",$period_at)) $this->error('凭证日期 格式错误');
            $period = date('Ym', strtotime($period.'-01'));
            $period_at = strtotime($period_at);
            if($period != date('Ym',$period_at)) $this->error('凭证日期不在凭证期间月份之内');
            $description = $req->param('description','');
            $market = $req->param('market','');
            $item = $req->param('item',[]);
            if(empty($item) || count($item) < 2) $this->error('凭证分录至少为两条');
            if(!$period) $this->error('请设置凭证周期');
            if(!$description) $this->error('请设置凭证摘要');

            if(ErpVoucherPeriod::where('period', $period)->where('luck',1)->find()) $this->error('该会计期间已锁帐、请更换期间');
            $period_code = ErpVoucherPeriod::where('period', $period)->max('period_code');
            if(!$period_code) {
                $period_code = $period . '0001';
            } else {
                $period_code = $period_code + 1;
            }

            $debit = 0;
            $credit = 0;
            $time = time();

            foreach($item as $k=>$val) {
                if($val['debit'] <= 0 && $val['credit'] <= 0)  $this->error('凭证分录借贷双方不能均为0值');
                if($val['debit'] > 0 && $val['credit'] > 0)  $this->error('凭证分录借贷双方不能均为大于0的值');
                $debit += round($val['debit'],2);
                $credit += round($val['credit'],2);
                $item[$k]['position'] = $k;
                $item[$k]['period'] = $period;
                $item[$k]['period_code'] = $period_code;
                $item[$k]['period_at'] = $period_at;
                $item[$k]['create_at'] = $time;
                $item[$k]['update_at'] = $time;
            }
            if($debit != $credit)  $this->error('凭证的借贷双方金额不一致！');
            $info = [
                'period'        => $period,//凭证期间
                'period_code'   => $period_code,//凭证号
                'description'   => $description,//摘要
                'market'        => $market,//备注
                'create_uid'    => max($this->adminId,0),//制表人
                'create_at'     => $time,//
                'update_at'     => $time
            ];
            ErpVoucherPeriod::beginTrans();
            try {
                $res = ErpVoucherPeriod::create($info);
                if (!$res) {
                    throw new \think\Exception('凭证主表存入失败！');
                }
                $voucher = new ErpVoucher();
                $res = $voucher->saveAll($item);
                if (!$res) {
                    throw new \think\Exception('凭证副表存入失败！');
                }
                ErpVoucherPeriod::commitTrans();
            } catch (\Exception $e) {
                ErpVoucherPeriod::rollbackTrans();
                $this->error($e->getMessage());
            }
            $this->success('操作成功!');
        }
        $this->assign('period', date('Y-m'));
        $this->assign('period_day', date('Y-m-d'));
        return $this->fetch();
    }

    /**
     * 更新资源
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function edit(Request $req)
    {
        $period_code = $req->param('period_code/d',0);
        if(!$period_code) $this->error('参数错误','', -1);
        $period = ErpVoucherPeriod::where('period_code', $period_code)->find();
        if(!$period) $this->error('参数错误','', -1);
        if($period['luck']==1)  $this->error('所属会计期间已锁帐、不能执行此操作','',-1);
        if($period['status']==1)  $this->error('凭证已审核、不能执行此操作','',-1);
        if($req->isPost()) {
            $period_at = $req->param('period_at','');
            $description = $req->param('description','');
            $market = $req->param('market','');
            $item = $req->param('item',[]);
            if(!$description) $this->error('请设置凭证摘要');
            if(empty($item) || count($item) < 2) $this->error('凭证分录至少为两条');
            if(!preg_match("/^\d{4}-\d{2}-\d{2}$/s",$period_at)) $this->error('凭证日期 格式错误');
            $period_at = strtotime($period_at);
            if($period['period'] != date('Ym',$period_at)) $this->error('凭证日期不在凭证期间月份之内');

            $debit = 0;
            $credit = 0;
            $time = time();
            $ids = ErpVoucher::where('period_code','=',$period_code)->column('id');
            $new_ids = [];
            foreach($item as $k=>$val) {
                if($val['id'] > 0) {
                    $new_ids[] = $val['id'];
                } else {
                    unset($item[$k]['id']);
                    $item[$k]['create_at'] = $time;
                }
                if($val['debit'] <= 0 && $val['credit'] <= 0)  $this->error('凭证分录借贷双方不能均为0值');
                if($val['debit'] > 0 && $val['credit'] > 0)  $this->error('凭证分录借贷双方不能均为大于0的值');
                $debit += round($val['debit'],2);
                $credit += round($val['credit'],2);
                $item[$k]['position'] = $k;
                $item[$k]['period_at'] = $period_at;
                $item[$k]['period'] = $period['period'];
                $item[$k]['period_code'] = $period['period_code'];
                $item[$k]['update_at'] = $time;
            }
            if($debit != $credit) $this->error('凭证的借贷双方金额不一致！');
            $del_ids = array_diff($ids, $new_ids);
            $info = [
                'description'   => $description,//摘要
                'market'        => $market,//备注
                'create_uid'    => max($this->adminId,0),//制表人
                'update_at'     => $time
            ];
            ErpVoucherPeriod::beginTrans();
            try {
                $res = ErpVoucherPeriod::where('period_code','=',$period_code)->update($info);
                if (!$res) {
                    throw new \think\Exception('凭证主表存入失败！');
                }
                $voucher = new ErpVoucher();
                $res = $voucher->saveAll($item);
                if (!$res) {
                    throw new \think\Exception('凭证副表存入失败！');
                }
                if(!empty($del_ids)) {
                    $res = $voucher->where('id','IN',$del_ids)->delete();
                    if (!$res) {
                        throw new \think\Exception('移除的凭证删除失败！');
                    }
                }
                ErpVoucherPeriod::commitTrans();
            } catch (\Exception $e) {
                ErpVoucherPeriod::rollbackTrans();
                $this->error($e->getMessage());
            }
            $this->success('操作成功!');
        }

        $data = [];
        $debit = 0;
        $credit = 0;
        $num = 0;
        $period_day = '';
        $vouchers = $period->vouchers()->order('position ASC')->select()->toArray();
        foreach($vouchers as $voucher) {
            if(!$period_day && $voucher['period_at']) $period_day = date('Y-m-d', $voucher['period_at']);
            $num++;
            $debit += round($voucher['debit'],2);
            $credit += round($voucher['credit'],2);
            $data['list'][] = [
                'id' => $voucher['id'],
                'code' => $voucher['code'],
                'code_name' => $voucher['code_name'],
                'debit' => $voucher['debit'] ? number_format($voucher['debit'],2,'.','') : '0.00',
                'credit' => $voucher['credit'] ? number_format($voucher['credit'],2,'.','') : '0.00',
            ];
        }
        $data['id'] = $period['id'];
        $data['period_day'] = $period_day;
        $data['num'] = $num;
        $data['period'] = $period['period'];
        $data['period_code'] = $period['period_code'];
        $data['description'] = $period['description'];
        $data['market'] = $period['market'];
        $data['debit'] = $debit ? number_format($debit,2,'.','') : '0.00';
        $data['credit'] = $credit ? number_format($credit,2,'.','') : '0.00';

        $sonAuth = SystemMenus::getSonAuth($req->controller(), $req->action(),array_keys($this->auth));
        $this->assign('sonAuth', $sonAuth);
        $this->assign('data', $data);
        return $this->fetch();
    }

    /**
     * 删除
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function del(Request $req)
    {
        if($req->isAjax()) {
            $period_code = $req->param('period_code/d', 0);
            if (!$period_code) $this->error('参数错误');
            $period = ErpVoucherPeriod::where('period_code', $period_code)->find();
            if (!$period) $this->error('参数错误');
            if($period['luck']==1)  $this->error('所属会计期间已锁帐、不能执行此操作');
            if($period['status']==1)  $this->error('已审核、不能执行此操作');
            ErpVoucherPeriod::beginTrans();
            try {
                $res = ErpVoucherPeriod::where('id',$period['id'])->delete();
                if(!$res) {
                    throw new \think\Exception('凭证主表删除失败！');
                }
                $res = ErpVoucher::where('period_code',$period['period_code'])->delete();
                if(!$res) {
                    throw new \think\Exception('凭证副表删除失败！');
                }
                if($period['order_no']) {
                    $res = ErpVoucher::delOrder($period_code,$period['order_no']);
                    if(!$res) {
                        throw new \think\Exception('关联订单处理失败！');
                    }
                }
                ErpVoucherPeriod::commitTrans();
            } catch (\Exception $e) {
                ErpVoucherPeriod::rollbackTrans();
                $this->error($e->getMessage());
            }
            $this->success('操作成功!');
        }
    }
}
